package com.zhg.videorecord.helper;

import android.annotation.SuppressLint;
import android.graphics.ImageFormat;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.util.Log;

import java.util.Arrays;


/**
 * desc:  todo
 * author: ZHG
 * date: 2019/11/21
 */
public class CodectUtil {
    private static final String TAG = "MediaCodecUtil";

    private static byte[] yuv420spToYuv420P(byte[] yuv420spData, int width, int height) {
        byte[] yuv420pData = new byte[width * height * 3 / 2];
        int ySize = width * height;
        System.arraycopy(yuv420spData, 0, yuv420pData, 0, ySize);   //拷贝 Y 分量

        for (int j = 0, i = 0; j < ySize / 2; j += 2, i++) {
            yuv420pData[ySize + i] = yuv420spData[ySize + j];   //U 分量
            yuv420pData[ySize * 5 / 4 + i] = yuv420spData[ySize + j + 1];   //V 分量
        }
        return yuv420pData;
    }


    private void yuv420pTo420sp(byte[] yuv420p, byte[] yuv420sp, int width, int height) {
        if (yuv420p == null || yuv420sp == null) {
            return;
        }
        int frameSize = width * height;
        int j;
        System.arraycopy(yuv420p, 0, yuv420sp, 0, frameSize);
        for (j = 0; j < frameSize / 4; j++) {
            // u
            yuv420sp[frameSize + 2 * j] = yuv420p[j + frameSize];
            // v
            yuv420sp[frameSize + 2 * j + 1] = yuv420p[(int) (j + frameSize * 1.25)];
        }
    }

    /**
     * Generates the presentation time for frame N, in microseconds.
     */
    public static long computePresentationTime(long frameIndex) {
        return 132 + frameIndex * 1000000 / 30;
    }

    @Deprecated
    public static void converNV21ToNV12(byte[] nv21, byte[] nv12, int width, int height) {
        if (nv21 == null || nv12 == null) {
            return;
        }
        int framesize = width * height;
        int i = 0, j = 0;
        System.arraycopy(nv21, 0, nv12, 0, framesize);
        for (i = 0; i < framesize; i++) {
            nv12[i] = nv21[i];
        }
        for (j = 0; j < framesize / 2; j += 2) {
            nv12[framesize + j - 1] = nv21[j + framesize];
        }
        for (j = 0; j < framesize / 2; j += 2) {
            nv12[framesize + j] = nv21[j + framesize - 1];
        }
    }

    /**
     * desc:
     *
     * @framesize width*height
     * author: ZHG
     * date: 2020/4/19
     */
    public static void convertNv21ToNv12(byte[] nv21, byte[] nv12, int framesize) {
        if (nv21 == null || nv12 == null) {
            return;
        }
        System.arraycopy(nv21, 0, nv12, 0, framesize);
        for (int i = 0; i < framesize / 2 - 1; i += 2) {
            //nv21:uvuvuvuv nv21[]=16,18,20,22,
            //nv12=17,19,21,23
            //j=0,nv12[]
            nv12[i + framesize] = nv21[i + framesize + 1];
            nv12[i + framesize + 1] = nv21[i + framesize];
        }
        int a = 0;
    }

    public static void YUV420spRotate90(byte[] des, final byte[] src, int width,
                                        int height) {
        int n = 0;
        int hw = width / 2;
        int hh = height / 2;
        // copy y
        for (int j = 0; j < width; j++) {
            for (int i = height - 1; i >= 0; i--) {
                des[n++] = src[width * i + j];
            }
        }

        int pos = width * height;
        for (int j = 0; j < width; j += 2) {
            for (int i = hh - 1; i >= 0; i--) {
                des[n++] = src[pos + width * i + j];        // copy v
                des[n++] = src[pos + width * i + j + 1];    // copy u
            }
        }
    }

    public static byte[] nv21Rotate90(byte[] nv21_data, int width, int height) {
        int y_size = width * height;
        int buffser_size = y_size * 3 / 2;
        byte[] nv21_rotated = new byte[buffser_size];
        // rotate the y luma


        int i = 0;
        int startpos = (height - 1) * width;
        for (int x = 0; x < width; x++) {
            int offset = startpos;
            for (int y = height - 1; y >= 0; y--) {
                nv21_rotated[i] = nv21_data[offset + x];
                i++;
                offset -= width;
            }
        }

        // rotate the u and v color components
        i = buffser_size - 1;
        for (int x = width - 1; x > 0; x = x - 2) {
            int offset = y_size;
            for (int y = 0; y < height / 2; y++) {
                nv21_rotated[i] = nv21_data[offset + x];
                i--;
                nv21_rotated[i] = nv21_data[offset + (x - 1)];
                i--;
                offset += width;
            }
        }
        return nv21_rotated;
    }


    @SuppressLint("NewApi")
    public static void getSuportMediaCodecColorFormat() {
        //获取解码器列表
        int numCodecs = MediaCodecList.getCodecCount();
        MediaCodecInfo codecInfo = null;
        for (int i = 0; i < numCodecs && codecInfo == null; i++) {
            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
            if (!info.isEncoder()) {
                continue;
            }
            String[] types = info.getSupportedTypes();
            boolean found = false;
            //轮训所要的解码器
            for (int j = 0; j < types.length && !found; j++) {
                if (types[j].equals("video/avc")) {
                    System.out.println("found");
                    found = true;
                }
            }
            if (!found) {
                continue;
            }
            codecInfo = info;
        }
        Log.d(TAG, "found" + codecInfo.getName() + "supporting" + " video/avc");


        //检查设备所支持的colorspace
        int colorFormat = 0;
        MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType("video/avc");
        System.out.println("length-" + capabilities.colorFormats.length + "==" + Arrays.toString(capabilities.colorFormats));
        for (int i = 0; i < capabilities.colorFormats.length && colorFormat == 0; i++) {
            int format = capabilities.colorFormats[i];
            //COLOR_FormatYUV420Planar /COLOR_FormatYUV420SemiPlanar/COLOR_FormatYUV420Flexible
            //COLOR_FormatSurface
            Log.i(TAG, "支持的色彩空间格式:" + getFormatName(format));
        }
        Log.d(TAG, "color format " + colorFormat);
    }

    private static String getFormatName(int format) {
        String name = "";
        int value = format;
        /*if (format>50){
            value=
        }*/
        if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatMonochrome) {
            name = "COLOR_FormatMonochrome";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_Format8bitRGB332) {
            name = "COLOR_Format8bitRGB332";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_Format8bitRGB332) {
            name = "COLOR_Format8bitRGB332";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411Planar) {
            name = "COLOR_FormatYUV411Planar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV411PackedPlanar) {
            name = "COLOR_FormatYUV411PackedPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) {
            name = "COLOR_FormatYUV420Planar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar) {
            name = "COLOR_FormatYUV420PackedPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
            name = "COLOR_FormatYUV420SemiPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV422Planar) {
            name = "COLOR_FormatYUV422Planar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV422PackedPlanar) {
            name = "COLOR_FormatYUV422PackedPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV422SemiPlanar) {
            name = "COLOR_FormatYUV422SemiPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar) {
            name = "COLOR_FormatYUV420PackedSemiPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV422PackedSemiPlanar) {
            name = "COLOR_FormatYUV422PackedSemiPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar) {
            name = "COLOR_TI_FormatYUV420PackedSemiPlanar";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface) {
            name = "COLOR_FormatSurface";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible) {
            name = "COLOR_FormatYUV420Flexible";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV422Flexible) {
            name = "COLOR_FormatYUV422Flexible";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_Format8bitRGB332) {
            name = "COLOR_Format8bitRGB332";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_Format8bitRGB332) {
            name = "COLOR_Format8bitRGB332";
        } else if (value == MediaCodecInfo.CodecCapabilities.COLOR_Format8bitRGB332) {
            name = "COLOR_Format8bitRGB332";
        } else {
            name = format + "";
        }
        return name;
    }

    public static String getImageFormatName(int format) {
        String name;
        if (format == ImageFormat.NV21) {
            name = "NV21";
        } else if (format == ImageFormat.YV12) {
            name = "YV12";
            //}else if (format == ImageFormat.y) {
            //    name = "YV12";
            //}else if (format == ImageFormat.YV21) {
            //    name = "NV21";
        } else {
            name = format + "";
        }
        return name;
    }

    private static void print(String tag, byte[] data) {
        for (int i = 0; i < data.length; i++) {
            Log.i("test", tag + "-i" + data[i]);
        }
    }

    public static byte[] frameMirror(byte[] data, int width, int height) {
        byte tempData;
        for (int i = 0; i < height * 3 / 2; i++) {
            for (int j = 0; j < width / 2; j++) {
                tempData = data[i * width + j];
                data[i * width + j] = data[(i + 1) * width - 1 - j];
                data[(i + 1) * width - 1 - j] = tempData;
            }

        }
        return data;
    }

   public static byte[] NV21_mirror(byte[] nv21_data, int width, int height) {
        int i;
        int left, right;
        byte temp;
        int startPos = 0;

        // mirror Y
        for (i = 0; i < height; i++) {
            left = startPos;
            right = startPos + width - 1;
            while (left < right) {
                temp = nv21_data[left];
                nv21_data[left] = nv21_data[right];
                nv21_data[right] = temp;
                left++;
                right--;
            }
            startPos += width;
        }


        // mirror U and V
        int offset = width * height;
        startPos = 0;
        for (i = 0; i < height / 2; i++) {
            left = offset + startPos;
            right = offset + startPos + width - 2;
            while (left < right) {
                temp = nv21_data[left];
                nv21_data[left] = nv21_data[right];
                nv21_data[right] = temp;
                left++;
                right--;

                temp = nv21_data[left];
                nv21_data[left] = nv21_data[right];
                nv21_data[right] = temp;
                left++;
                right--;
            }
            startPos += width;
        }
        return nv21_data;
    }


}
